"""
FastAPI backend for message monitoring.
- Exposes REST endpoints for dashboard data, control, and preview images.
- Serves a simple React + Ant Design frontend from / (static HTML).
"""
import threading
from collections import deque
from typing import Deque, List, Tuple, Optional, Dict, Any

from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import Response

from admin_utils import AdminUtils
from message_monitor import MessageMonitor

# -------------------- State --------------------
_msgs_lock = threading.Lock()
_all_msgs: Deque[Tuple[str, str, str]] = deque(maxlen=500)
_hit_msgs: Deque[Tuple[str, str, str]] = deque(maxlen=500)

_monitor: Optional[MessageMonitor] = None


def _listener(now: str, pairs: List[Tuple[str, str]], hits: List[Tuple[str, str]]):
    with _msgs_lock:
        for name, msg in pairs:
            _all_msgs.append((now, name or "未知", msg or ""))
        for name, msg in hits:
            _hit_msgs.append((now, name or "未知", msg or ""))


def get_monitor() -> MessageMonitor:
    global _monitor
    if _monitor is None:
        # Default config similar to main.py
        _monitor = MessageMonitor(
            window_title="星痕共鸣",
            keywords=["娜宝", "银娜", "金娜", "神奇动物", "粉猪", "金猪"],
            rel_rect=(0.0301, 0.6, 0.2, 0.89),
            interval_sec=0.5,
            ocr_lang="chi_sim",
            debug_preview=False,
        )
        _monitor.add_listener(_listener)
    return _monitor


app = FastAPI(title="XHGM Monitor API", version="0.1.0")

# Allow local frontend usage if opened directly
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


# -------------------- API Routes --------------------
@app.get("/api/dashboard")
def api_dashboard(limit: int = 100) -> Dict[str, Any]:
    """返回仪表盘所需的所有数据，包括状态、消息等"""
    m = get_monitor()

    # 获取状态信息
    preview_stages = {"raw": False, "cleaned": False, "ocr": False}
    try:
        with m._last_preview_lock:  # type: ignore[attr-defined]
            preview_stages["raw"] = getattr(m, "_last_raw_image", None) is not None
            preview_stages["cleaned"] = getattr(m, "_last_cleaned_image", None) is not None
    except Exception:
        preview_stages = {"raw": False, "cleaned": False}

    # 获取消息数据
    limit = max(1, min(500, int(limit or 100)))
    with _msgs_lock:
        all_list = list(_all_msgs)[-limit:]
        hit_list = list(_hit_msgs)[-limit:]

        # 返回统一的数据结构
        return {
            # 状态信息
            "status": {
                "running": getattr(m, "_running", False),
                "keywords": m.keywords,
                "all_count": len(_all_msgs),
                "hit_count": len(_hit_msgs),
                "debug_preview": bool(getattr(m, "debug_preview", False)),
                "preview_available": any(preview_stages.values()),
                "preview_stages": preview_stages,
            },
            # 消息数据
            "messages": {
                "all": [{"time": t, "name": n, "msg": m} for (t, n, m) in all_list],
                "hits": [{"time": t, "name": n, "msg": m} for (t, n, m) in hit_list],
            }
        }


@app.post("/api/start")
def api_start():
    AdminUtils.require_admin()  # ensure admin for screen capture and window control
    m = get_monitor()
    m.start()
    return {"ok": True}


@app.post("/api/stop")
def api_stop():
    m = get_monitor()
    m.stop()
    return {"ok": True}


@app.post("/api/keywords")
def api_set_keywords(payload: Dict[str, Any]):
    m = get_monitor()
    kws = payload.get("keywords")
    if not isinstance(kws, list):
        raise HTTPException(status_code=400, detail="keywords must be a list")
    # normalize and deduplicate
    cleaned = []
    for k in kws:
        if not isinstance(k, str):
            continue
        k = k.strip()
        if not k:
            continue
        if k not in cleaned:
            cleaned.append(k)
    m.keywords = [k.lower() for k in cleaned]
    return {"ok": True, "keywords": m.keywords}


@app.post("/api/debug_preview")
def api_toggle_debug_preview(payload: Dict[str, Any]):
    m = get_monitor()
    enable = bool(payload.get("enable", True)) if isinstance(payload, dict) else True
    if enable:
        m.enable_debug_preview()
    else:
        m.disable_debug_preview()
    return {"ok": True, "debug_preview": m.debug_preview}


@app.get("/api/preview/{stage}")
def api_get_preview_stage(stage: str):
    m = get_monitor()
    stage = (stage or "").lower()
    if stage not in ("raw", "cleaned"):
        raise HTTPException(status_code=400, detail="stage must be one of raw|cleaned|ocr")
    try:
        with m._last_preview_lock:  # type: ignore[attr-defined]
            if stage == "raw":
                img = getattr(m, "_last_raw_image", None)
            else:
                img = getattr(m, "_last_cleaned_image", None)
            if img is None:
                raise HTTPException(status_code=404, detail="no preview available for stage")
            import io
            buf = io.BytesIO()
            img.save(buf, format="PNG")
            data = buf.getvalue()
            return Response(content=data, media_type="image/png")
    except HTTPException:
        raise
    except Exception:
        raise HTTPException(status_code=500, detail="failed to render preview stage")
